// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "targetver.h"
#include <stdio.h>
#include <tchar.h>
#include <shellapi.h>
#include "Vfw.h"
#include <MMSystem.h>
#include <Winioctl.h>

#pragma data_seg ("shared")
HINSTANCE hCallInst = NULL;// muc dich co* nay la` tranh viec nguoi dung de` Ctrl + KEY lau dan~ den mo~ hang` loai app
DllData Data = {0,0,'\0',{'\0'},-1};

#pragma data_seg ()

#pragma comment(linker,"/SECTION:shared,RWS")

bool bOpenCD;
bool bOnTop;
int nCount = 0;
LPTSTR str = new TCHAR[1000];

#define EXPORT __declspec(dllexport)

EXPORT BOOL SetHook(HINSTANCE);
EXPORT void RemoveHook();

EXPORT LRESULT CALLBACK KeyToolProc(int nCode,WPARAM wParam,LPARAM lParam);

EXPORT bool OpenCloseTray(bool bOpen);

EXPORT LPTSTR getValue(int x);

EXPORT void OnTop(HWND hWnd, int &b);

HHOOK hHook;
HMODULE hMd;

// cac ham thao tac voi DllData
EXPORT void CALLBACK setToolState(int);		//DUNG DE SET TRANG THAI CUNG CHG TRINH

EXPORT BOOL CALLBACK AddHotKey(int QKey_1, int QKey_2, int QKey_3,TCHAR* szAppPath, int Flag);		// them 1 record cho quick app
EXPORT void CALLBACK RemoveQuickApp(int x);	
		BOOL IsQuickAppExists(int QKey_1, int QKey_2, int QKey_3);

EXPORT DllData CALLBACK GetDataInfo();
 
EXPORT void SetDllData(DllData &Data);

EXPORT void LoadAppList(HWND handle);

EXPORT int getCountApp();

EXPORT void AddKey(HWND handle);

EXPORT void SetUpDown( BOOL bState, int iUpDown );
//

void LoadData();
LPTSTR getValueKeyboard(int x);
LPTSTR getHotKey(int x);
bool isHotKeyValid(int QKey_1, int QKey_2, int QKey_3);
int getMod(int x);

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
					 )
{
	hMd = hModule;
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:
		
		break;
	case DLL_PROCESS_DETACH:
		//RemoveHook();		
		UnhookWindowsHookEx(hHook);
		break;
	}
	return TRUE;
}


EXPORT BOOL SetHook(HINSTANCE hInst)
{	
	if (hCallInst != NULL)
		return FALSE;

	hCallInst = hInst;

	hHook = SetWindowsHookEx(WH_GETMESSAGE,(HOOKPROC)KeyToolProc,hMd,0);
	LoadData();
	
	bOpenCD = true;

	return TRUE;
}


int getPath(int a[3], int Count)
{
	for(int i = 0; i < Data.nCountApp; i++)
		if ((Data.arrAppKeyList[i].HotKey_1 == -1) && (Data.arrAppKeyList[i].HotKey_2 == a[1]) 
			&& (Data.arrAppKeyList[i].HotKey_3 == a[2])
			||
			(Data.arrAppKeyList[i].HotKey_2 == -1) && (Data.arrAppKeyList[i].HotKey_1 == a[1]) 
			&& (Data.arrAppKeyList[i].HotKey_3 == a[2])
			||
			(Data.arrAppKeyList[i].HotKey_3 == 0) && (Data.arrAppKeyList[i].HotKey_1 == a[1]) 
			&& (Data.arrAppKeyList[i].HotKey_2 == a[2]))
			return i;
		else 
			if ((Data.arrAppKeyList[i].HotKey_1 == a[1]) && (Data.arrAppKeyList[i].HotKey_2 == a[2]) 
			&& (Data.arrAppKeyList[i].HotKey_3 == a[3]))
				return i;
	return -1;
}

EXPORT LRESULT CALLBACK KeyToolProc(int nCode,WPARAM wParam,LPARAM lParam){
	// cac msg khong xu ly
	if (nCode < 0)
		return CallNextHookEx(NULL,nCode,wParam,lParam);

	// xu ly msg:
	MSG *pMsg = (MSG*)lParam;
	//TCHAR cHKey1
	int a[10];
	int bPath;

	switch (pMsg->message){
		case WM_KEYDOWN:
			//if (pMsg->wParam == VK_CONTROL)
			//		break;
			
			if (pMsg->wParam == VK_CONTROL || pMsg->wParam == VK_MENU)
				break;

				nCount = 0;

				if (GetKeyState(VK_CONTROL) < 0)
				{
					++nCount;
					a[nCount] = VK_CONTROL;
				}

				if (GetKeyState(VK_MENU) < 0)
				{
					++nCount;
					a[nCount] = VK_MENU;
				}

				if (GetKeyState(VK_SHIFT) < 0)
				{
					++nCount;
					a[nCount] = VK_SHIFT;
				}

				if (GetKeyState(VK_LWIN) < 0)
				{
					++nCount;
					a[nCount] = VK_LWIN;
				}
				
				
				if (nCount == 2 /*|| nCount == 1*/)
				{
					if (pMsg->wParam >= 65)
					{
					++nCount;
					a[nCount] = pMsg->wParam;
					}

					int bPath = getPath(a, nCount);
					if (bPath == -1)
					{
						int Temp;
						Temp = a[1];
						a[1] = a[2];
						a[2] = Temp;

						bPath = getPath(a, nCount);
					}

					if (bPath != -1)
						switch(Data.iFlag[bPath])
						{
						case ID_SHUTDOWN:
							ExitWindowsEx(EWX_SHUTDOWN  | EWX_POWEROFF |EWX_FORCE,0);
							break;
						case ID_RESTART:
							ExitWindowsEx(EWX_REBOOT | EWX_FORCE,0);
							break;
						case ID_LOGOFF:
							ExitWindowsEx(EWX_LOGOFF,SHTDN_REASON_FLAG_PLANNED);
							break;
						case ID_STANDBY:
							SetSystemPowerState(TRUE,TRUE);
							break;
						case ID_HIBERNATE:
							SetSystemPowerState(FALSE,FALSE);
							break;
						case ID_APP:
							ShellExecute(NULL,NULL,Data.szAppPathList[bPath],NULL,NULL,SW_SHOW);
							break;
						case ID_EJECTCD:
							OpenCloseTray(bOpenCD);
							bOpenCD = !bOpenCD;
							break;
						case ID_ONTOP:
							OnTop(GetActiveWindow(), Data.bOnTop[bPath]);
							break;
						case ID_SCREENOFF:
							SendMessage(HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, (LPARAM) 2);
							break;
						case ID_VOLDOWN:
							for (int i = 0; i < 6; i++)
								SetUpDown( TRUE,VK_VOLUME_DOWN );
							break;
						case ID_VOLUP:
							for (int i = 0; i < 6; i++)
								SetUpDown( TRUE,VK_VOLUME_UP );
							break;
						}
					
					nCount = 0;
				}
			break;
		case WM_KEYUP:
			break;
	}
	return CallNextHookEx(NULL,nCode,wParam,lParam);
}

// cac ham thao tac voi DllData
/*EXPORT void CALLBACK setToolState(int flag){		//DUNG DE SET TRANG THAI CUNG CHG TRINH
	Data.iFlag+=flag;
}*/

EXPORT BOOL CALLBACK AddHotKey(int QKey_1, int QKey_2, int QKey_3,TCHAR* szAppPath, int Flag){		// them 1 record cho quick app
	if (IsQuickAppExists(QKey_1, QKey_2, QKey_3) 
		|| !isHotKeyValid(QKey_1, QKey_2, QKey_3))
		return FALSE;
	Data.arrAppKeyList[Data.nCountApp].HotKey_1 = QKey_1;
	Data.arrAppKeyList[Data.nCountApp].HotKey_2 = QKey_2;
	Data.arrAppKeyList[Data.nCountApp].HotKey_3 = QKey_3;

	_tcscpy(Data.szAppPathList[Data.nCountApp],szAppPath);
	Data.iFlag[Data.nCountApp] = Flag;

	if (Data.iFlag[Data.nCountApp] == ID_ONTOP)
		Data.bOnTop[Data.nCountApp] = 0;

	Data.nCountApp++;
	return TRUE;
}
EXPORT void CALLBACK RemoveQuickApp(int x)
{
	int i = x;
	
	for(;i < Data.nCountApp-1; i++){
		Data.arrAppKeyList[i] = Data.arrAppKeyList[i+1];
		_tcscpy(Data.szAppPathList[i],Data.szAppPathList[i+1]);
	}
	Data.nCountApp--;
//MessageBox(NULL,L"Da xoa rui ",L"aa",MB_OK);
}

BOOL IsQuickAppExists(int QKey_1, int QKey_2, int QKey_3){
	for(int i = 0; i < Data.nCountApp; i++)
		if ((Data.arrAppKeyList[i].HotKey_1 == QKey_1) && (Data.arrAppKeyList[i].HotKey_2 == QKey_2) && (Data.arrAppKeyList[i].HotKey_3 == QKey_3))
			return TRUE;
	return FALSE;
}

void RemoveHook(){
	TCHAR szPath[256];
	HANDLE hFile;
	DWORD nByteWritten;
	
		//save vao file:
		GetModuleFileName(hMd,szPath,sizeof(szPath));
		//MessageBox(NULL, szPath, _T("Thong Bao"), 0);
		int i;
		for (i = _tcslen(szPath); i>0; i--)
			if (szPath[i] == '\\')
				break;

			szPath[i+1] = '\0'; 
			//szPath[i+1] = '\0'; 
			_tcscat(szPath,L"HotKey.ini");

		if (INVALID_HANDLE_VALUE == 
			(hFile = CreateFile(szPath,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,NULL)))
				return;
		WriteFile(hFile,&Data,sizeof(DllData),&nByteWritten,NULL);
		CloseHandle(hFile);

	hCallInst = NULL;
}
void LoadData(){
	TCHAR szPath[256];
	HANDLE hFile;
	DWORD nByteRead;
	
	GetModuleFileName(hMd,szPath,sizeof(szPath));
	int i;
	for (i = _tcslen(szPath); i>0; i--)
		if (szPath[i] == '\\')
			break;

		szPath[i+1] = '\0'; 
		_tcscat(szPath,L"HotKey.ini");

	//Load:
		if (INVALID_HANDLE_VALUE ==
			(hFile = CreateFile(szPath,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL))){
	// neu doc khong duoc thi gan Struct Data ve gia tri def		
				DllData defVal = {0,0,'\0',{'\0'}};
				Data = defVal;
				return;
		}
			
		ReadFile(hFile,&Data,sizeof(DllData),&nByteRead,NULL);
		CloseHandle(hFile);
}
		
EXPORT DllData CALLBACK GetDataInfo(){
	return Data;
}

/*
TCHAR* ChuanHoaAppPath(TCHAR* szSource){
	static TCHAR szKQ[256];
	_tcscpy(szKQ,szSource);
	int n = _tcslen(szKQ);
	for (int  i = 0; i< n; i++){
		if (szKQ[i] == '\\'){
			for (int j = n; j > i ; j--)
				szKQ[j] = szKQ[j-1];
		n++;
		i++;
		}
	}
	szKQ[n++] = '\0';

	return szKQ;
}*/

EXPORT void SetDllData(DllData &Data)
{
	Data = Data;
}

EXPORT bool OpenCloseTray(bool bOpen)
{
    // Open the device (drive) that we want to affect
	DWORD nSystemDrives = GetLogicalDrives();
	TCHAR szDriveRoot[] = _T("x:\\");
	TCHAR cDrive;
	TCHAR* cs = new TCHAR[255];

	for(cDrive = 'A'; cDrive <= 'Z'; cDrive++, nSystemDrives >>= 1)
	{
        if(!(nSystemDrives & 1))
            continue;
	
		szDriveRoot[0] = cDrive;
		UINT nDriveType = GetDriveType(szDriveRoot);
	
		if(nDriveType == DRIVE_CDROM)
		{
			swprintf(cs, _T("\\\\.\\%c:"), cDrive);
			break;
		}
	}
	//MessageBox(hWnd, cs, _T("Thong Bao"), 0);
    //cs.Format(_T("\\\\.\\%c:"),cDrive);
    HANDLE hDrive = CreateFile(cs, GENERIC_READ, FILE_SHARE_READ, 
                               NULL, OPEN_EXISTING, 
    FILE_ATTRIBUTE_NORMAL, NULL);

    // Make sure the device was found and opened successfully
    if(hDrive == INVALID_HANDLE_VALUE || GetLastError() != NO_ERROR)
        return false;

    BOOL bStatus; // Let the caller know if it worked or not
    DWORD dwDummy; // We don't really need this info
    if(bOpen) // Open the tray
        bStatus = DeviceIoControl(hDrive, IOCTL_STORAGE_EJECT_MEDIA, NULL, 
                                  0, NULL, 0, &dwDummy, NULL);
    else // Close the tray
        bStatus = DeviceIoControl(hDrive, IOCTL_STORAGE_LOAD_MEDIA, 
                                  NULL, 0, NULL, 0, &dwDummy, NULL);
    CloseHandle(hDrive);
    return bStatus?true:false;
}

LPTSTR getHotKey(int x)
{
	LPTSTR str = new TCHAR[1000];
	wsprintf(str, _T(""));

	if (Data.arrAppKeyList[x].HotKey_1 != -1)
	{
	wcscat(str, getValueKeyboard(Data.arrAppKeyList[x].HotKey_1));
	wcscat(str, _T("+"));
	}

	if (Data.arrAppKeyList[x].HotKey_2 != -1)
	{
	wcscat(str, getValueKeyboard(Data.arrAppKeyList[x].HotKey_2));
	wcscat(str, _T("+"));
	}

	if (Data.arrAppKeyList[x].HotKey_3 != 0)
		wcscat(str, getValueKeyboard(Data.arrAppKeyList[x].HotKey_3));

	return str;
}

LPTSTR getValueKeyboard(int x)
{
	LPTSTR str = new TCHAR[1000];
	wsprintf(str, _T(""));

	switch (x)
	{
	case VK_CONTROL:
		return _T("Control");
	case VK_SHIFT:
		return _T("Shift");
	case VK_MENU:
		return _T("ALT");
	case VK_LWIN:
		return _T("WinDow");
	default:
		wsprintf(str, _T("%c"), x);
		return str;
	}
}

EXPORT LPTSTR getValue(int x)
{
	LPTSTR str = new TCHAR[1000];
	wsprintf(str, _T(""));

	switch (Data.iFlag[x])
		{
		case ID_APP:
			int j;
			for (j = _tcslen(Data.szAppPathList[x]); j>0; j--)
				if (Data.szAppPathList[x][j] == _T('\\'))
					break;
		
			wcscpy(str, &Data.szAppPathList[x][j+1]);
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			break;
		case ID_SHUTDOWN:
			wcscpy(str, _T("Shutdown"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			break;
		case ID_RESTART:
			wcscpy(str, _T("Restart"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			//wcscat(str, _T("\n"));
			break;
		case ID_LOGOFF:
			wcscpy(str, _T("Log Off"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			//wcscat(str, _T("\n"));
			break;
		case ID_STANDBY:
			wcscpy(str, _T("Stand By"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			//wcscat(str, _T("\n"));
			break;
		case ID_HIBERNATE:
			wcscpy(str, _T("Hibernate"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			//wcscat(str, _T("\n"));
			break;
		case ID_VOLUP:
			wcscpy(str, _T("Volume Up"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			break;
		case ID_VOLDOWN:
			wcscpy(str, _T("Volume Down"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			break;
		case ID_EJECTCD:
			wcscpy(str, _T("EJect CD"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			break;
		case ID_ONTOP:
			wcscpy(str, _T("On Top"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			break;
		case ID_ONTRAY:
			wcscpy(str, _T("On Tray"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			break;
		case ID_SCREENOFF:
			wcscpy(str, _T("Screen Off"));
			wcscat(str, _T("       "));
			wcscat(str, getHotKey(x));
			break;
		}
	return str;
}

EXPORT void LoadAppList(HWND handle)
{
	SetDllData(Data);
	wsprintf(str, _T(""));

	for (int i = 0; i < Data.nCountApp; i++)
	{
		str = getValue(i);
		SendMessage(handle,LB_ADDSTRING ,0,(LPARAM)str);		
	}
}

EXPORT int getCountApp()
{
	return Data.nCountApp;
}

EXPORT void AddKey(HWND handle)
{
	LPTSTR str = new TCHAR[1000];
	wsprintf(str, _T(""));

	str = getValue(Data.nCountApp-1);

	SendMessage(handle,LB_ADDSTRING ,0,(LPARAM)str);
}

EXPORT void SetUpDown( BOOL bState, int iUpDown )
   {
      BYTE keyState[256];

      GetKeyboardState((LPBYTE)&keyState);
	  if( (bState && !(keyState[iUpDown] & 1)) ||
		  (!bState && (keyState[iUpDown] & 1)) )
      {
      // Simulate a key press
		  keybd_event( iUpDown,
                      0x45,
                      KEYEVENTF_EXTENDEDKEY | 0,
                      0 );

      // Simulate a key release
		  keybd_event( iUpDown,
                      0x45,
                      KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP,
                      0);
      }
 }

EXPORT void OnTop(HWND hWnd, int &b)
{
	RECT rect;
	GetWindowRect(hWnd, &rect);

	if (b == 0)
	{
		SetWindowPos(hWnd, HWND_TOPMOST,rect.left, rect.top, rect.right-rect.left, rect.bottom - rect.top, NULL);
		b = 1;
	}
	else
	{
		SetWindowPos(hWnd, HWND_NOTOPMOST,rect.left, rect.top, rect.right-rect.left, rect.bottom - rect.top, NULL);

		b = 0;
	}

}

bool isHotKeyValid(int QKey_1, int QKey_2, int QKey_3)
{
	int x1 = getMod(QKey_1);
	int x2 = getMod(QKey_2);

	if (QKey_3 == 0)
		return true;

	if (x1 == 0)
		return RegisterHotKey(NULL, 1, x2, QKey_3);

	if (x2 == 0)
		return RegisterHotKey(NULL, 1, x1, (char)QKey_3);

	return RegisterHotKey(NULL, 1, x1 | x2, QKey_3);
}

int getMod(int x)
{
	switch(x)
	{
	case VK_CONTROL:
		return MOD_CONTROL;
	case VK_MENU:
		return MOD_ALT;
	case VK_SHIFT:
		return MOD_SHIFT;
	case VK_LWIN:
		return MOD_WIN;
	default:
		return 0;
	}
}